package com.swf.seed.triutil.lang;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.swf.seed.base.SystemContants;
import com.swf.seed.base.filter.Filter;
import com.swf.seed.base.filter.IFileOperator;
import com.swf.seed.base.filter.NameFilter;
import com.swf.seed.util.ClassLoaderUtils;

/**
 * 项目名称：common 类名称：FileUtils 类描述： 文件操作类 创建人：Weifeng Shen 创建时间：2012-12-28
 * 上午9:50:17
 * 
 * @version 1.0
 */
public final class SdFileUtils extends FileUtils {
	private static final Logger logger = LoggerFactory
			.getLogger(SdFileUtils.class);

	/**
	 * 禁用默认构造器
	 */
	private SdFileUtils() {
	}

	/**
	 * method:copyFile{复制文件从from目录到to目录}
	 * 
	 * @param from
	 *            来源目录
	 * @param to
	 *            目的目录
	 * @param fileName
	 *            文件名
	 */
	public static void copyFile(String fromDir, String toDir, String fileName) {
		String from =SdNameUtils.DealSeparator(fromDir);
		String to = SdNameUtils.DealSeparator(toDir);
		FileInputStream in = null;
		BufferedOutputStream out = null;
		byte[] buf = new byte[1024];
		try {
			in = new FileInputStream(new File(from, fileName));
			out = new BufferedOutputStream(new FileOutputStream(new File(to,
					fileName)), 1024);
			int len;
			while ((len = in.read(buf)) != -1) {
				out.write(buf, 0, len);
			}
			out.flush();
			out.close();
			logger.info("Copy file " + fileName + " from " + from + " to " + to
					+ " success");
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
	}

	/**
	 * 从相对与classPath的地方加载文件或者绝对路径获取文件内容
	 * 
	 * @param filePath
	 * @param encoding
	 * @return
	 */
	public static String loadFile(String filePath, String encoding) {
		StringBuffer fileContent = new StringBuffer();
		int len = 0;
		InputStream is = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		char[] buf = new char[1024];
		try {
			if (SdNameUtils.isRelativePath(filePath)) {
				is = ClassLoaderUtils.getStream(filePath);
			} else {
				is = new FileInputStream(filePath);
			}
			if (is == null) {
				throw new FileNotFoundException("资源文件不存在");
			}
			isr = new InputStreamReader(is, encoding);
			br = new BufferedReader(isr);
			while ((len = br.read(buf,0,1024)) != -1) {
				fileContent.append(buf,0,len);
			}
		} catch (MalformedURLException e) {
			logger.error(e.getMessage(), e);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		} finally {
			SdIOUtils.closeStream(br,isr,is);
		}
		return fileContent.toString();
	}

	public static String loadFile(File file, String encoding)
			throws FileNotFoundException {
		if (!file.exists()) {
			throw new FileNotFoundException("资源文件不存在");
		}
		return loadFile(file.getAbsolutePath(), encoding);
	}

	/**
	 * 复制文件
	 * 
	 * @param srcDir
	 *            源文件目录
	 * @param destDir
	 *            目标文件目录
	 * @param depth
	 *            复制的文件深度，设为0则不复制当前srcDir文件夹
	 * @param nameFilter
	 *            文件名称过滤器，null则不过滤
	 * @throws IOException
	 */
	public static void copyDir(String srcDir, String destDir, int depth,
			Filter nameFilter) throws IOException {
		File srcFile = new File(srcDir);
		if (nameFilter != null && !nameFilter.accept(srcFile.getName())) {
			logger.info("文件" + srcFile.getName() + "被过滤掉!");
			return;
		}
		File destFile = new File(destDir);
		if (srcFile.isDirectory() && !srcFile.getName().equals(".svn")) {
			if (depth > 0) {
				File newdestFile = new File(destDir);
				if (!newdestFile.exists()) {
					newdestFile.mkdirs();
					logger.info("生成文件：" + newdestFile.getAbsolutePath());
				}
			}
			File[] files = srcFile.listFiles();
			for (File file : files) {
				File newdestFile = new File(destDir, file.getName());
				copyDir(file.getAbsolutePath(),
						newdestFile.getAbsolutePath(), depth + 1, nameFilter);
			}
		} else if (srcFile.isFile()) {
			File newdestFile = new File(destDir);
			if (!newdestFile.exists()
					|| srcFile.lastModified() != newdestFile.lastModified()) {
				FileUtils.copyFile(srcFile, destFile);
			}
		}
	}

	/**
	 * 复制文件到指定目录，只复制修改过的
	 * 
	 * @param srcDir
	 * @param destDir
	 * @param depth
	 * @param nameFilter
	 * @throws IOException
	 */
	public static void copyFileToDir(String srcDir, String destDir, int depth,
			Filter nameFilter) throws IOException {
		File srcFile = new File(srcDir);
		File destFile = new File(destDir);
		if (srcFile.isDirectory()) {
			File[] files = srcFile.listFiles();
			for (File file : files) {
				File newDestFile = new File(destDir, file.getName());
				copyFileToDir(file.getAbsolutePath(),
						newDestFile.getAbsolutePath(), depth + 1, nameFilter);
			}
		} else if (srcFile.isFile()) {
			if (nameFilter != null && !nameFilter.accept(srcFile.getName())) {
				logger.debug("文件" + srcFile.getName() + "被过滤掉!");
				return;
			}
			File newdestFile = new File(getRootDestDir(destDir, depth),
					srcFile.getName());
			if (!newdestFile.exists()
					|| srcFile.lastModified() != newdestFile.lastModified()) {
				FileUtils.copyFile(srcFile, newdestFile);
				logger.info("copy File \"" + srcFile.getAbsolutePath()
						+ "\" to File \"" + newdestFile.getAbsolutePath());
			}
		}
	}

	public static void copyFileToDir(String srcDir, String destDir,
			Filter nameFilter) throws IOException {
		copyFileToDir(srcDir, destDir, 0, nameFilter);
	}

	public static void copyFileToDir(File srcFile, File destFile,
			Filter nameFilter) throws IOException {
		copyFileToDir(srcFile.getAbsolutePath(), destFile.getAbsolutePath(), 0,
				nameFilter);
	}

	private static String getRootDestDir(String destDir, int depth) {
		String destdir = SdNameUtils.DealSeparatorNone(destDir);
		for (int i = depth; i > 0; i--) {
			destdir = destdir.substring(0, destdir.lastIndexOf("/"));
		}
		return destdir;
	}

	/**
	 * 不设置过滤器，复制所有文件
	 * 
	 * @param srcDir
	 * @param destDir
	 * @param depth
	 * @throws IOException
	 */
	public static void copyDir(String srcDir, String destDir, int depth)
			throws IOException {
		copyDir(srcDir, destDir, depth, null);
	}

	/**
	 * 复制src下的文件到destDir目录下，不包括src目录
	 * 
	 * @param srcDir
	 * @param destDir
	 * @throws IOException
	 */
	public static void copyDir(String srcDir, String destDir)
			throws IOException {
		copyDir(srcDir, destDir, 1, null);
	}

	/**
	 * 复制文件
	 * 
	 * @param srcFile
	 * @param destFile
	 * @throws IOException
	 */
	public static void copyDir(File srcFile, File destFile) throws IOException {
		String srcDir = srcFile.getAbsolutePath();
		String destDir = destFile.getAbsolutePath();
		copyDir(srcDir, destDir);
	}

	/**
	 * 复制文件
	 * 
	 * @param srcFile
	 * @param destFile
	 * @throws IOException
	 */
	public static void copyDir(File srcFile, File destFile, int depth)
			throws IOException {
		String srcDir = srcFile.getAbsolutePath();
		String destDir = destFile.getAbsolutePath();
		copyDir(srcDir, destDir, depth);
	}

	/**
	 * 复制文件
	 * 
	 * @param srcFile
	 * @param destFile
	 * @throws IOException
	 */
	public static void copyDir(File srcFile, File destFile, int depth,
			Filter nameFilter) throws IOException {
		String srcDir = srcFile.getAbsolutePath();
		String destDir = destFile.getAbsolutePath();
		copyDir(srcDir, destDir, depth, nameFilter);
	}

	/**
	 * 删除目录
	 * 
	 * @param dirPath
	 */
	public static boolean deleteDir(String dirPath) {
		File directory = new File(dirPath);
		if (!canDelete(directory)) {
			return false;
		}
		try {
			FileUtils.deleteDirectory(directory);
			return true;
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			return false;
		}
	}

	/**
	 * 删除目录
	 * 
	 * @param directory
	 */
	public static boolean deleteDir(File directory) {
		if (!canDelete(directory))
			return false;
		try {
			FileUtils.deleteDirectory(directory);
			return true;
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			return false;
		}
	}

	/**
	 * 删除指定深度的目录，0表示删除当前目录，1表示删除当前目录下一级文件及目录
	 * 
	 * @param directory
	 * @param depth
	 */
	public static void deleteDir(File directory, int depth) {
		if (!directory.exists()) {
			Exception e = new FileNotFoundException("目录或文件不存在");
			logger.error(e.getMessage(), e);
		}
		if (!canDelete(directory))
			return;
		if (depth > 0) {
			if (directory.isDirectory()) {
				File[] files = directory.listFiles();
				for (File file : files) {
					deleteDir(file, depth - 1);
				}
			}
		} else {
			if (deleteFileOrDirectory(directory))
				logger.info("删除文件:" + directory.getAbsolutePath());
		}
	}

	public static boolean deleteFileOrDirectory(File file) {
		if (!canDelete(file))
			return false;
		if (file.isFile())
			return file.delete();
		if (file.isDirectory()) {
			return deleteDir(file);
		}
		return false;
	}

	/**
	 * 删除目录
	 * 
	 * @param dirPath
	 *            删除目录
	 * @param nameFilter
	 *            名称过滤器
	 */
	public static void deleteDir(String dirPath,NameFilter nameFilter) {
		File directory = new File(dirPath);
		if (!directory.isDirectory())
			return;
		if (nameFilter != null && nameFilter.accept(directory.getName())) {
			if (deleteDir(directory)) {
				logger.info("目录" + directory.getAbsolutePath() + "被删除!");
			}
			return;
		}
		File[] files = directory.listFiles();
		for (File file : files) {
			deleteDir(file.getAbsolutePath(), nameFilter);
		}
	}

	/**
	 * 删除文件
	 * 
	 * @param dirPath
	 *            删除目录下的文件
	 * @param nameFilter
	 *            名称过滤器
	 */
	public static void deleteFiles(String dirPath, NameFilter nameFilter) {
		File directory = new File(dirPath);
		if (directory.isFile() && nameFilter != null
				&& nameFilter.accept(directory.getName())) {
			if (canDelete(directory)) {
				directory.delete();
				logger.info("文件" + directory.getAbsolutePath() + "被删除!");
			}
			return;
		}
		if (directory.isDirectory()) {
			File[] files = directory.listFiles();
			for (File file : files) {
				deleteFiles(file.getAbsolutePath(), nameFilter);
			}
		}
	}

	/**
	 * 如果该路径是一个合法的目录路径，创建该目录
	 * 
	 * @param dirPath
	 */
	public static void makeDir(String dirPath) {
		File directory = new File(dirPath);
		if (directory.isDirectory()) {
			directory.mkdir();
		} else {
			logger.warn("this is not a directory");
		}
	}

	/**
	 * 判断文件是否可以删除
	 * 
	 * @param file
	 * @return
	 */
	public static boolean canDelete(File file) {
		return file.renameTo(file);
	}

	/**
	 * 判断文件是否可以删除
	 * 
	 * @param fileName
	 * @return
	 */
	public static boolean canDelete(String fileName) {
		File file = new File(fileName);
		return file.renameTo(file);
	}

	/**
	 * 根据路径获取文件，可以是相对与classPath路径或者绝对路径
	 * 
	 * @param filePath
	 * @return
	 */
	public static File getFile(String filePath) {
			if (SdNameUtils.isRelativePath(filePath)) {
				return ClassLoaderUtils.getFile(filePath);
			} else {
				return new File(filePath);
			}
	}
	
	
	 /**
	  * 创建一个新文件
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static boolean createNewFile(File file) throws IOException {
			 File dir = new File(file.getParent());
			 dir.mkdirs();
			 return file.createNewFile();
	 }

	/**
	 * 遍历文件夹
	 * 
	 * @param file
	 *            目录
	 * @param filter
	 *            文件过滤器
	 * @param operator
	 *            文件操作类
	 */
	public static void goThrough(File file, Filter filter,
			IFileOperator operator) {
		if (file == null || !file.exists()) {
			return;
		}
		if (file.isFile() && file.canRead() && file.canWrite()
				&& file.canExecute()) {
			if (filter == null || filter.accept(file.getName())) {
				if (operator != null) {
					operator.execute(file);
				}
			}
		} else if (file.isDirectory() && file.canRead()) {
			File[] files = file.listFiles();
			for (File child : files) {
				goThrough(child, filter, operator);
			}
		}
	}
	
	/**
	 * 获取文件的后缀名
	 * @param fileName 文件名称
	 * @return
	 */
	public static String getFileSuffix(String fileName){
		if (fileName==null){
			return "";
		}
		int index = fileName.lastIndexOf('.');
		if (index!=-1){
			return fileName.substring(index+1);
		}else{
			return "";
		}
	}
	
	/**
	 * 根据路径获取文件，可以是相对与classPath路径或者绝对路径
	 * 
	 * @param filePath
	 * @return
	 */
	public static File getUserDirFile(String filePath) {
		return new File(SystemContants.PROJECT_PATH,filePath);
	}
	
}
